#ifndef _AMERICO_VECTOR2_H_
#define _AMERICO_VECTOR2_H_

#include <cassert>
#include <cmath>
#include "staticarray.h"

template <typename TYPE>
class Vector2
{
public:
    union
    {
        TYPE myX, x;
        TYPE myR, r;
		TYPE myU, u;
    };
    union
    {
        TYPE myY, y;
        TYPE myG, g;
		TYPE myV, v;
    };

    Vector2();
	Vector2(const Vector2 &aVector);
    Vector2(const TYPE &aX, const TYPE &aY);
    ~Vector2();

	Vector2 &operator=(const Vector2 &aVector);

    Vector2 operator-() const;
    Vector2 operator+(const Vector2 &aVector) const;
    Vector2 operator-(const Vector2 &aVector) const;
    Vector2 operator*(const Vector2 &aVector) const;
    Vector2 operator*(const TYPE &aScalar) const;
	Vector2 operator/(const Vector2 &aVector) const;
    Vector2 operator/(const TYPE &aScalar) const;

    Vector2 &operator+=(const Vector2 &aVector);
    Vector2 &operator-=(const Vector2 &aVector);
    Vector2 &operator*=(const Vector2 &aVector);
    Vector2 &operator*=(const TYPE &aScalar);
	Vector2 &operator/=(const Vector2 &aVector);
    Vector2 &operator/=(const TYPE &aScalar);

	bool operator==(const Vector2 &aVector) const;
	bool operator!=(const Vector2 &aVector) const;

	void Set(const TYPE &aX, const TYPE &aY);

    float Length() const;
	float Length2() const;
	float LengthSqr() const;
    TYPE Dot(const Vector2 &aVector) const;

	Vector2 &Rotate(const float &anAngle);
	Vector2 Clone();
	Vector2 &Normalize();
};



template <typename TYPE>
Vector2<TYPE>::Vector2()
{
}

template <typename TYPE>
Vector2<TYPE>::Vector2(const Vector2<TYPE> &aVector)
{
	myX = aVector.myX;
	myY = aVector.myY;
}

template <typename TYPE>
Vector2<TYPE>::Vector2(const TYPE &aX, const TYPE &aY)
{
    myX = aX;
    myY = aY;
}

template <typename TYPE>
Vector2<TYPE>::~Vector2()
{
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::operator=(const Vector2<TYPE> &aVector)
{
	myX = aVector.myX;
	myY = aVector.myY;
	return *this;
}

template <typename TYPE>
Vector2<TYPE> Vector2<TYPE>::operator-() const
{
    Vector2<TYPE> result(-myX, -myY);
    return result;
}

template <typename TYPE>
Vector2<TYPE> Vector2<TYPE>::operator+(const Vector2<TYPE> &aVector) const
{
    Vector2<TYPE> result(*this);
    result += aVector;
    return result;
}

template <typename TYPE>
Vector2<TYPE> Vector2<TYPE>::operator-(const Vector2<TYPE> &aVector) const
{
    Vector2<TYPE> result(*this);
    result -= aVector;
    return result;
}

template <typename TYPE>
Vector2<TYPE> Vector2<TYPE>::operator*(const Vector2<TYPE> &aVector) const
{
    Vector2<TYPE> result(*this);
    result *= aVector;
    return result;
}

template <typename TYPE>
Vector2<TYPE> Vector2<TYPE>::operator*(const TYPE &aScalar) const
{
    Vector2<TYPE> result(*this);
    result *= aScalar;
    return result;
}

template <typename TYPE>
Vector2<TYPE> Vector2<TYPE>::operator/(const Vector2<TYPE> &aVector) const
{
    Vector2<TYPE> result(*this);
    result /= aVector;
    return result;
}

template <typename TYPE>
Vector2<TYPE> Vector2<TYPE>::operator/(const TYPE &aScalar) const
{
    Vector2<TYPE> result(*this);
    result /= aScalar;
    return result;
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::operator+=(const Vector2<TYPE> &aVector)
{
    myX += aVector.myX;
    myY += aVector.myY;
    return *this;
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::operator-=(const Vector2<TYPE> &aVector)
{
    myX -= aVector.myX;
    myY -= aVector.myY;
    return *this;
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::operator*=(const Vector2<TYPE> &aVector)
{
    myX *= aVector.myX;
    myY *= aVector.myY;
    return *this;
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::operator*=(const TYPE &aScalar)
{
    myX *= aScalar;
    myY *= aScalar;
    return *this;
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::operator/=(const Vector2<TYPE> &aVector)
{
	assert(((aVector.x!=0) && (aVector.y!=0)) && "Division by 0");
    myX /= aVector.x;
    myY /= aVector.y;
    return *this;
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::operator/=(const TYPE &aScalar)
{
	assert(aScalar!=0 && "Division by 0");
    myX /= aScalar;
    myY /= aScalar;
    return *this;
}

template <typename TYPE>
bool Vector2<TYPE>::operator==(const Vector2<TYPE> &aVector) const
{
	return ((myX == aVector.myX) && (myY == aVector.myY));
}

template <typename TYPE>
bool Vector2<TYPE>::operator!=(const Vector2<TYPE> &aVector) const
{
	return ! operator==(aVector);
}

template <typename TYPE>
void Vector2<TYPE>::Set(const TYPE &aX, const TYPE &aY)
{
	myX = aX;
	myY = aY;
}

template <typename TYPE>
float Vector2<TYPE>::Length() const
{
    return sqrt(myX*myX+myY*myY);
}

template <typename TYPE>
float Vector2<TYPE>::Length2() const
{
	return (myX*myX+myY*myY);
}

template <typename TYPE>
float Vector2<TYPE>::LengthSqr() const
{
	return (myX*myX+myY*myY);
}

template <typename TYPE>
TYPE Vector2<TYPE>::Dot(const Vector2<TYPE> &aVector) const
{
    return (myX*aVector.myX+myY*aVector.myY);
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::Rotate(const float &anAngle)
{
	Vector2<TYPE> temp(*this);
	float cosA = cos(anAngle);
	float sinA = sin(anAngle);
	myX = temp.x * cosA - temp.y * sinA;
	myY = temp.x * sinA + temp.y * cosA;
	return *this;
}

template <typename TYPE>
Vector2<TYPE> Vector2<TYPE>::Clone()
{
	return Vector2<TYPE>(*this);
}

template <typename TYPE>
Vector2<TYPE> &Vector2<TYPE>::Normalize()
{
    TYPE length = Length();
	if(length>0)
	{
		myX /= length;
		myY /= length;
	}
	return *this;
}

#endif
